;/***************************************************************************
; * Copyright (c) 2024 Microsoft Corporation 
; * 
; * This program and the accompanying materials are made available under the
; * terms of the MIT License which is available at
; * https://opensource.org/licenses/MIT.
; * 
; * SPDX-License-Identifier: MIT
; **************************************************************************/
;
;
;/**************************************************************************/
;/**************************************************************************/
;/**                                                                       */ 
;/** ThreadX Component                                                     */ 
;/**                                                                       */
;/**   Thread                                                              */
;/**                                                                       */
;/**************************************************************************/
;/**************************************************************************/
;
;
;#define TX_SOURCE_CODE
;
;
;/* Include necessary system files.  */
;
;#include "tx_api.h"
;#include "tx_thread.h"
;#include "tx_timer.h"
;
;
    extern __tx_thread_system_state
    extern __tx_thread_current_ptr
    extern __tx_thread_preempt_disable
    extern __tx_thread_execute_ptr
    extern __tx_timer_time_slice
    extern __tx_thread_schedule

    section .text:CODE:ROOT

;/**************************************************************************/ 
;/*                                                                        */ 
;/*  FUNCTION                                               RELEASE        */ 
;/*                                                                        */ 
;/*    _tx_thread_context_restore                           RXv3/IAR       */
;/*                                                           6.1.11       */
;/*  AUTHOR                                                                */ 
;/*                                                                        */ 
;/*    William E. Lamie, Microsoft Corporation                             */
;/*                                                                        */ 
;/*  DESCRIPTION                                                           */ 
;/*                                                                        */ 
;/*    This function restores the interrupt context if it is processing a  */ 
;/*    nested interrupt.  If not, it returns to the interrupt thread if no */ 
;/*    preemption is necessary.  Otherwise, if preemption is necessary or  */ 
;/*    if no thread was running, the function returns to the scheduler.    */ 
;/*                                                                        */ 
;/*  INPUT                                                                 */ 
;/*                                                                        */ 
;/*    None                                                                */ 
;/*                                                                        */ 
;/*  OUTPUT                                                                */ 
;/*                                                                        */ 
;/*    None                                                                */ 
;/*                                                                        */ 
;/*  CALLS                                                                 */ 
;/*                                                                        */ 
;/*    _tx_thread_schedule                   Thread scheduling routine     */ 
;/*                                                                        */ 
;/*  CALLED BY                                                             */ 
;/*                                                                        */ 
;/*    ISRs                                  Interrupt Service Routines    */ 
;/*                                                                        */ 
;/*  RELEASE HISTORY                                                       */ 
;/*                                                                        */ 
;/*    DATE              NAME                      DESCRIPTION             */ 
;/*                                                                        */ 
;/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
;/*  10-15-2021     William E. Lamie         Modified comment(s), and      */ 
;/*                                            added FPU support,          */ 
;/*                                            resulting in version 6.1.9  */ 
;/*  01-31-2022     William E. Lamie         Modified comment(s),          */
;/*                                            resulting in version 6.1.10 */
;/*  04-25-2022     William E. Lamie         Modified comment(s),          */
;/*                                            resulting in version 6.1.11 */
;/*                                                                        */ 
;/**************************************************************************/ 
    public __tx_thread_context_restore

__tx_thread_context_restore:
;
;    /* Lockout interrupts.  */

     CLRPSW I                                   ; Disable interrupts

;    /* Determine if interrupts are nested.  */
;    if (--_tx_thread_system_state)
;    {

     MOV.L    #__tx_thread_system_state, R1
     MOV.L    [R1], R2
     SUB      #1, R2
     MOV.L    R2,[R1]
     BEQ      __tx_thread_not_nested_restore 

;
;    /* Interrupts are nested.  */
;
;    /* Recover the saved registers from the interrupt stack
;       and return to the point of interrupt.  */
;
__tx_thread_nested_restore:
     POPC    FPSW                               ; Restore FPU status   
     POPM    R14-R15                            ; Restore R14-R15
     POPM    R3-R5                              ; Restore R3-R5
     POPM    R1-R2                              ; Restore R1-R2
     RTE                                        ; Return to point of interrupt, restore PSW including IPL
;    }

__tx_thread_not_nested_restore:
;
;    /* Determine if a thread was interrupted and no preemption is required.  */
;    else if (((_tx_thread_current_ptr) && (_tx_thread_current_ptr == _tx_thread_execute_ptr))
;               || (_tx_thread_preempt_disable))
;    {
    
     MOV.L    #__tx_thread_current_ptr, R1      ; Pickup current thread ptr address
     MOV.L    [R1], R2
     CMP      #0, R2
     BEQ      __tx_thread_idle_system_restore 
     
     MOV.L    #__tx_thread_preempt_disable, R3  ; Pick up preempt disable flag
     MOV.L    [R3], R3
     CMP      #0, R3
     BNE      __tx_thread_no_preempt_restore    ; If pre-empt disable flag set, we simply return to the original point of interrupt regardless
     
     MOV.L    #__tx_thread_execute_ptr, R3      ; (_tx_thread_current_ptr != _tx_thread_execute_ptr)
     CMP      [R3], R2
     BNE      __tx_thread_preempt_restore       ; Jump to pre-empt restoring
;
__tx_thread_no_preempt_restore:
     SETPSW  U                                  ; User stack
     POPC    FPSW                               ; Restore FPU status
     POPM    R14-R15                            ; Restore R14-R15
     POPM    R3-R5                              ; Restore R3-R5
     POPM    R1-R2                              ; Restore R1-R2
     RTE                                        ; Return to point of interrupt, restore PSW including IPL

;    }
;    else
;    {

__tx_thread_preempt_restore:

;    /* Save the remaining time-slice and disable it.  */
;    if (_tx_timer_time_slice)
;    {

     MOV.L    #__tx_timer_time_slice, R3        ; Pickup time-slice address
     MOV.L    [R3],R4                           ; Pickup actual time-slice
     CMP      #0, R4
     BEQ      __tx_thread_dont_save_ts          ; No time-slice to save
;
;        _tx_thread_current_ptr -> tx_thread_time_slice =  _tx_timer_time_slice;
;        _tx_timer_time_slice =  0;
;
     MOV.L    R4,24[R2]                         ; Save thread's time slice
     MOV.L    #0,R4                             ; Clear value
     MOV.L    R4,[R3]                           ; Disable global time slice flag
;    }
__tx_thread_dont_save_ts:
;
;   /* Now store the remaining registers!   */

     SETPSW   U                                 ; User stack
     PUSHM    R6-R13
     
     MVFACGU   #0, A1, R4                       ; Save accumulators.
     MVFACHI   #0, A1, R5
     MVFACLO   #0, A1, R6
     PUSHM     R4-R6
     MVFACGU   #0, A0, R4
     MVFACHI   #0, A0, R5
     MVFACLO   #0, A0, R6
     PUSHM     R4-R6
     
#if (__DPFPU == 1)
    MOV.L   144[R2], R4                         ; Get tx_thread_fpu_enable.
    CMP     #0, R4
    BEQ     __tx_thread_preempt_restore_fpu_skip

    DPUSHM.D DR0-DR15                           ; Save FPU register bank if tx_thread_fpu_enable is not 0.
    DPUSHM.L DPSW-DECNT

__tx_thread_preempt_restore_fpu_skip:
#endif

;
;    /* Clear the current task pointer.  */
;    _tx_thread_current_ptr =  TX_NULL;
;    R1 ->  _tx_thread_current_ptr
;    R2 -> *_tx_thread_current_ptr

     MOV.L   R0,8[R2]                           ; Save thread's stack pointer in thread control block
     MOV.L   #0,R2                              ; Build NULL value
     MOV.L   R2,[R1]                            ; Set current thread to NULL

;    /* Return to the scheduler.  */
;    _tx_thread_schedule();

__tx_thread_idle_system_restore:
     MVTC    #0, PSW                            ; Reset interrupt priority level to 0
     BRA     __tx_thread_schedule               ; Jump to scheduler
;    }
;
;}
;
    END

